跳到主要内容

desktopCapturer 怎么做屏幕采集?权限卡在哪里?

考察点​

  • 采集 API 已经在主进程
  • macOS 屏幕录制权限和系统音频是分开的

参考答案​

1. 现在的用法​

desktopCapturer.getSources 在主进程调用。渲染进程只负责 getUserMedia 或 getDisplayMedia,源由主进程选定。

const { desktopCapturer, systemPreferences } = require('electron');

ipcMain.handle('capture:sources', async () => {
const sources = await desktopCapturer.getSources({
types: ['screen', 'window'],
thumbnailSize: { width: 320, height: 180 },
fetchWindowIcons: false,
});
// 只把 id、name、缩略图给页面,不把模块本身暴露出去
return sources.map((s) => ({
id: s.id,
name: s.name,
thumbnail: s.thumbnail.toDataURL(),
}));
});

页面选中某个 id 后,用 session.setDisplayMediaRequestHandler 把这个源交给 getDisplayMedia:

session.defaultSession.setDisplayMediaRequestHandler((_request, callback) => {
// 使用用户刚选中的 source,而不是默默取第一个屏幕
callback({ video: selectedSource });
});

2. macOS 权限​

  • 屏幕内容:需要屏幕录制权限。systemPreferences.getMediaAccessStatus('screen') 查询。没有权限时,getSources 可能只拿到空窗口或应用自己的窗口
  • 系统音频:macOS 14.2 之后还要在 Info.plist 里声明音频采集用途,否则只有画面没有系统声音
  • 权限是按签名记的。开发时授给 Electron,正式包要再授一次,授完通常要重启应用

Windows 没有同等的屏幕录制弹窗,但系统设置里仍可能限制后台采集。

3. 缩略图的成本​

每个窗口都会截一张图。窗口多时把 thumbnailSize 调小,或者只要列表不要预览时把宽高设成 0。不要用定时器连续 getSources,那是 CPU 和权限检查的双重浪费。

4. 安全​

采集到的画面是用户桌面,可能包含其他应用的内容。不要自动上传。开始采集前有明确的 UI,结束时停掉 MediaStream 的所有 track。

面试话术​

源列表在主进程用 desktopCapturer.getSources 拿,页面只收到 id 和缩略图。真正开流用 setDisplayMediaRequestHandler 把用户选中的源交出去。macOS 要屏幕录制权限,系统声音是另一条用途声明。开发签名和正式签名的授权不共享。缩略图按需生成,采集内容不自动上传。

常见追问​

  • 和 getUserMedia 共享屏幕的关系? Chromium 的选择器在 Electron 里经常不可用,所以要自己列源,再用 display media handler 接上。
  • Linux 呢? Wayland 下经常只能拿到一个合成后的源,和 X11 行为不同,要单独测。